package com.gzhryc.net_marketing.cloud.account.services;

import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.gzhryc.common.ClassTools;
import com.gzhryc.common.IDTools;
import com.gzhryc.common.NumberTools;
import com.gzhryc.common.StringTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.json.JsonTools;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.net_marketing.cloud.MarketConstants;
import com.gzhryc.net_marketing.cloud.PayCallbackUtils;
import com.gzhryc.net_marketing.cloud.account.services.models.WXPayDepositRefundOrder;
import com.gzhryc.pay.adaptation.alipay.AlipayNativeService;
import com.gzhryc.pay.adaptation.alipay.DefaultAlipayConfig;
import com.gzhryc.pay.adaptation.alipay.enums.EAliPayNormalTradeState;
import com.gzhryc.pay.adaptation.alipay.msg.native_pay.AlipayNativePayNotify;
import com.gzhryc.pay.adaptation.weixin.DefaultWXPayConfig;
import com.gzhryc.pay.adaptation.weixin.WXPayNativeService;
import com.gzhryc.pay.adaptation.weixin.enums.EWXPayNormalPayState;
import com.gzhryc.pay.adaptation.weixin.msg.native_pay.WXPayNativeOrderResponse;
import com.gzhryc.pay.adaptation.weixin.msg.native_pay.WXPayNativePayNotify;
import com.gzhryc.pay.adaptation.weixin.msg.native_pay.WXPayNativeQueryResponse;
import com.gzhryc.pay.adaptation.weixin.msg.native_pay.WXPayNativeRefundResponse;
import com.gzhryc.pay.enums.TradeType;
import com.gzhryc.shared_device.base.enums.EPayType;
import com.gzhryc.shared_device.common.payment.dao.db.AlipayConfig;
import com.gzhryc.shared_device.common.payment.dao.db.WXPayConfig;
import com.gzhryc.shared_device.common.payment.services.AlipayConfigService;
import com.gzhryc.shared_device.common.payment.services.WXPayConfigService;
import com.gzhryc.net_marketing.cloud.account.dao.CloudPayAccountDepositOrderDao;
import com.gzhryc.net_marketing.cloud.account.dao.db.CloudPayAccount;
import com.gzhryc.net_marketing.cloud.account.dao.db.CloudPayAccountDepositOrder;
import com.gzhryc.net_marketing.cloud.account.dao.enums.CloudPayAccountDepositOrderEnum;
import com.gzhryc.net_marketing.cloud.account.services.dto.CloudPayAccountDepositOrderSearch;
import org.apache.commons.lang3.StringUtils;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

public class CloudPayAccountDepositOrderService {

    static Logger log = Logger.getLogger(CloudPayAccountDepositOrderService.class);

    public static CloudPayAccountDepositOrderService self() {
        return MultiDBTools.getService(MarketConstants.JDBC_KEY,CloudPayAccountDepositOrderService.class, true);
    }

    CloudPayAccountDepositOrderDao dao;

    public CloudPayAccountDepositOrderService(String jdbcKey) {
        this.dao = new CloudPayAccountDepositOrderDao(jdbcKey);
    }

    public List<CloudPayAccountDepositOrder> findBySearch(CloudPayAccountDepositOrderSearch search, Integer pageNo, Integer pageLimit){
        Conditions conditions = dao.buildConditions(search);
        conditions.desc("createDate");
        try {
            return dao.findByCondition(conditions,pageNo,pageLimit);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public Long countBySearch(CloudPayAccountDepositOrderSearch search){
        Conditions conditions = dao.buildConditions(search);
        try {
            return dao.count(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return 0L;
    }

    public void payResult(WXPayNativePayNotify resultNotify){
        CloudPayAccountDepositOrder order = getByTradeNo(resultNotify.getOut_trade_no());
        if (order != null) {
            // 检查金额
            if (!order.getPayMoney().equals(resultNotify.getAmount().getTotal())) {
                // throw new LogicException("支付金额不正确");
                log.error("支付金额不正确，回调信息：" + JsonTools.toJson(resultNotify));
            }

            JdbcSession.begin();
            try {
                Conditions condition = new Conditions(CloudPayAccountDepositOrder.class);
                condition.and().is("tradeNo", order.getTradeNo());
                condition.and().is("state",CloudPayAccountDepositOrderEnum.State.WaitPay.index());

                CloudPayAccountDepositOrder updateEntity = new CloudPayAccountDepositOrder();
                updateEntity.setExternalTradeNo(resultNotify.getTransaction_id());
                updateEntity.setExternalContent(JsonTools.toJson(resultNotify));
                updateEntity.setReceiptMoney(resultNotify.getAmount().getTotal());
                updateEntity.setPayDate(new Date());
                if(resultNotify.getPayer() != null) {
                    updateEntity.setPayerId(resultNotify.getPayer().getOpenid());
                }
                if (EWXPayNormalPayState.SUCCESS.name().equals(resultNotify.getTrade_state())) {
                    updateEntity.setState(CloudPayAccountDepositOrderEnum.State.Finish.index());
                } else {
                    updateEntity.setState(CloudPayAccountDepositOrderEnum.State.Fail.index());
                }
                if (dao.updateNotNull(updateEntity, condition) > 0) {
                    order.setExternalTradeNo(updateEntity.getExternalTradeNo());
                    order.setExternalContent(updateEntity.getExternalContent());
                    order.setReceiptMoney(updateEntity.getReceiptMoney());
                    order.setPayDate(updateEntity.getPayDate());
                    order.setPayerId(updateEntity.getPayerId());
                    order.setState(updateEntity.getState());

                    if(CloudPayAccountDepositOrderEnum.State.Finish.index().equals(order.getState())) {
                        if (CloudPayAccountService.self().recharge(order)) {
                            JdbcSession.commit();
                            log.info("{{0}}账号充值成功，充值金额：{{1}}", order.getAccountId(), order.getPayMoney());
                        }
                    }else{
                        JdbcSession.commit();
                    }
                }else{
                    log.error("修改终端订单失败，订单信息：{{0:json}}",order);
                }
            } catch (SQLException e) {
                log.error("支付解决处理错误", e);
            }catch (LogicException e) {
                log.error(e.getMessage(),e);
            }finally {
                JdbcSession.end();
            }
        }else {
            log.error("未能找到支付订单，回调内容：{{0:json}}",resultNotify);
        }
    }

    public void payResult(AlipayNativePayNotify resultNotify){
        CloudPayAccountDepositOrder order = getByTradeNo(resultNotify.getTradeNo());
        if (order != null) {
            // 检查金额
            if (!order.getPayMoney().equals(resultNotify.getMoney())) {
                // throw new LogicException("支付金额不正确");
                log.error("支付金额不正确，回调信息：" + JsonTools.toJson(resultNotify));
            }

            JdbcSession.begin();
            try {
                Conditions condition = new Conditions(CloudPayAccountDepositOrder.class);
                condition.and().is("tradeNo", order.getTradeNo());
                condition.and().is("state",CloudPayAccountDepositOrderEnum.State.WaitPay.index());

                CloudPayAccountDepositOrder updateEntity = new CloudPayAccountDepositOrder();
                updateEntity.setExternalTradeNo(resultNotify.getExternalTradeNo());
                updateEntity.setExternalContent(JsonTools.toJson(resultNotify));
                updateEntity.setReceiptMoney(resultNotify.getMoney());
                updateEntity.setPayDate(new Date());
                if (EAliPayNormalTradeState.TRADE_SUCCESS.equals(resultNotify.getTradeStatus())) {
                    updateEntity.setState(CloudPayAccountDepositOrderEnum.State.Finish.index());
                } else {
                    updateEntity.setState(CloudPayAccountDepositOrderEnum.State.Fail.index());
                }
                if (dao.updateNotNull(updateEntity, condition) > 0) {
                    order.setExternalTradeNo(updateEntity.getExternalTradeNo());
                    order.setExternalContent(updateEntity.getExternalContent());
                    order.setReceiptMoney(updateEntity.getReceiptMoney());
                    order.setPayDate(updateEntity.getPayDate());
                    order.setPayerId(updateEntity.getPayerId());
                    order.setState(updateEntity.getState());

                    if(CloudPayAccountDepositOrderEnum.State.Finish.index().equals(order.getState())) {
                        if (CloudPayAccountService.self().recharge(order)) {
                            JdbcSession.commit();
                            log.info("{{0}}账号充值成功，充值金额：{{1}}", order.getAccountId(), order.getPayMoney());
                        }
                    }else{
                        JdbcSession.commit();
                    }
                }else{
                    log.error("修改终端订单失败，订单信息：{{0:json}}",order);
                }
            } catch (SQLException e) {
                log.error("支付解决处理错误", e);
            }catch (LogicException e) {
                log.error(e.getMessage(),e);
            }finally {
                JdbcSession.end();
            }
        }else {
            log.error("未能找到支付订单，回调内容：{{0:json}}",resultNotify);
        }
    }

    public CloudPayAccountDepositOrder getByTradeNo(String tradeNo){
        if(StringTools.isNotBlank(tradeNo)){
            try {
                return dao.getById(tradeNo);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public CloudPayAccountDepositOrder getJoinByTradeNo(String tradeNo){
        if(StringTools.isNotBlank(tradeNo)){
            try {
                return dao.getJoinById(tradeNo);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public CloudPayAccountDepositOrder getWaitPayOrder(Long accountId){
        if(accountId != null){
            Conditions conditions = new Conditions(CloudPayAccountDepositOrder.class);
            conditions.and().is("accountId",accountId);
            conditions.and().is("state",CloudPayAccountDepositOrderEnum.State.WaitPay.index());

            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public CloudPayAccountDepositOrder createWXPayDepositOrder(CloudPayAccount cloudPayAccount,Integer money) throws LogicException {
        if(cloudPayAccount != null && money != null){
            if(cloudPayAccount.getWxpayAppId() == null){
                throw new LogicException("云支付账号未配置微信支付");
            }
            WXPayConfig wxPayConfig = WXPayConfigService.self().getByAppId(cloudPayAccount.getWxpayAppId());
            if(wxPayConfig == null){
                throw new LogicException("未找到微信支付配置");
            }

            CloudPayAccountDepositOrder order = new CloudPayAccountDepositOrder();
            order.setTradeNo(cloudPayAccount.getId() + IDTools.getTimestampSecondID());
            order.setTitle("用户充值金额" + NumberTools.getMoneyStr(money));
            order.setAccountId(cloudPayAccount.getId());
            order.setPayType(EPayType.WXPay.index());
            order.setTradeType(TradeType.NativePay.name());
            order.setAppId(wxPayConfig.getAppId());
            order.setBusinessAccount(wxPayConfig.getMchId());
            order.setNotifyUrl(PayCallbackUtils.getPayNativeNotifyUrl(wxPayConfig));
            order.setPayMoney(money);
            order.setState(CloudPayAccountDepositOrderEnum.State.WaitPay.index());
            order.setCreateDate(new Date());

            DefaultWXPayConfig defaultWXPayConfig = ClassTools.copy(new DefaultWXPayConfig(),wxPayConfig);
            defaultWXPayConfig.setPayNativeNotifyUrl(PayCallbackUtils.getPayNativeNotifyUrl(wxPayConfig));

            try {
                WXPayNativeService wxpayNativeService = new WXPayNativeService(defaultWXPayConfig);
                WXPayNativeOrderResponse wxpayApiResp = wxpayNativeService.applyNativeOrder(order);
                if(wxpayApiResp != null && StringUtils.isNotBlank(wxpayApiResp.getCode_url())){
                    order.setPayDate(new Date());
                    order.setExternalContent(wxpayApiResp.getCode_url());
                    if(dao.insert(order) > 0){
                        return order;
                    }
                }else{
                    log.error("{{0}}账号充值创建微信Native支付返回失败，AppID = {{1}}，返回结果：{{2:json}}",cloudPayAccount.getId()
                            ,wxPayConfig.getAppId(),wxpayApiResp);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public CloudPayAccountDepositOrder createAlipayDepositOrder(CloudPayAccount cloudPayAccount,Integer money) throws LogicException {
        if(cloudPayAccount != null && money != null){
            if(cloudPayAccount.getAlipayAppId() == null){
                throw new LogicException("云支付账号未配置支付宝支付");
            }
            AlipayConfig alipayConfig = AlipayConfigService.self().getByAppId(cloudPayAccount.getAlipayAppId());
            if(alipayConfig == null){
                throw new LogicException("未找到支付宝支付配置");
            }

            CloudPayAccountDepositOrder order = new CloudPayAccountDepositOrder();
            order.setTradeNo(cloudPayAccount.getId() + IDTools.getTimestampSecondID());
            order.setTitle("用户充值金额" + NumberTools.getMoneyStr(money));
            order.setAccountId(cloudPayAccount.getId());
            order.setPayType(EPayType.Alipay.index());
            order.setTradeType(TradeType.NativePay.name());
            order.setAppId(alipayConfig.getAppId());
            order.setBusinessAccount(alipayConfig.getPid());
            //order.setNotifyUrl(alipayConfig.getPayNativeNotifyUrl());
            order.setPayMoney(money);
            order.setState(CloudPayAccountDepositOrderEnum.State.WaitPay.index());
            order.setCreateDate(new Date());

            DefaultAlipayConfig defaultAlipayConfig = ClassTools.copy(new DefaultAlipayConfig(),alipayConfig);
            defaultAlipayConfig.setPayNotifyUrl(PayCallbackUtils.getPayNativeNotifyUrl(alipayConfig));

            try {
                AlipayNativeService nativeService = new AlipayNativeService(defaultAlipayConfig);
                AlipayTradePrecreateResponse apiResp = nativeService.applyNativeOrder(order);
                if(apiResp != null && StringUtils.isNotBlank(apiResp.getQrCode())){
                    order.setPayDate(new Date());
                    order.setExternalContent(apiResp.getQrCode());
                    if(dao.insert(order) > 0){
                        return order;
                    }
                }else{
                    log.error("{{0}}账号充值创建支付宝Native支付返回失败，AppID = {{1}}，返回结果：{{2:json}}",cloudPayAccount.getId()
                            ,alipayConfig.getAppId(),apiResp);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public boolean synExternalPayOrder(CloudPayAccountDepositOrder order) throws LogicException {
        CloudPayAccount cloudPayAccount = CloudPayAccountService.self().getById(order.getAccountId());
        if(cloudPayAccount.getWxpayAppId() == null){
            throw new LogicException("云支付账号未配置第三方支付");
        }
        WXPayConfig wxPayConfig = WXPayConfigService.self().getByAppId(cloudPayAccount.getWxpayAppId());
        if(wxPayConfig == null){
            throw new LogicException("未找到第三方支付(微信)");
        }
        DefaultWXPayConfig defaultWXPayConfig = ClassTools.copy(new DefaultWXPayConfig(),wxPayConfig);

        boolean result = false;
        JdbcSession.begin();
        try {
            WXPayNativeService wxpayNativeService = new WXPayNativeService(defaultWXPayConfig);
            WXPayNativeQueryResponse apiResp = wxpayNativeService.queryByTradeNo(order.getTradeNo());
            if(apiResp != null && StringTools.isNotBlank(apiResp.getTrade_state())) {
                Conditions condition = new Conditions(CloudPayAccountDepositOrder.class);
                condition.and().is("tradeNo", order.getTradeNo());
                condition.and().is("state",CloudPayAccountDepositOrderEnum.State.WaitPay.index());

                CloudPayAccountDepositOrder updateEntity = new CloudPayAccountDepositOrder();
                updateEntity.setTradeNo(order.getTradeNo());
                updateEntity.setExternalTradeNo(apiResp.getTransaction_id());
                updateEntity.setExternalContent(JsonTools.toJson(apiResp));
                updateEntity.setReceiptMoney(apiResp.getAmount().getTotal());
                updateEntity.setPayDate(new Date());
                if (apiResp.getPayer() != null) {
                    updateEntity.setPayerId(apiResp.getPayer().getOpenid());
                }
                if (EWXPayNormalPayState.SUCCESS.equals(apiResp.getTrade_state())) {
                    updateEntity.setState(CloudPayAccountDepositOrderEnum.State.Finish.index());
                } else {
                    updateEntity.setState(CloudPayAccountDepositOrderEnum.State.Fail.index());
                }

                if (dao.updateNotNull(updateEntity,condition) > 0) {
                    order.setExternalTradeNo(updateEntity.getExternalTradeNo());
                    order.setExternalContent(updateEntity.getExternalContent());
                    order.setReceiptMoney(updateEntity.getReceiptMoney());
                    order.setPayDate(updateEntity.getPayDate());
                    order.setPayerId(updateEntity.getPayerId());
                    order.setState(updateEntity.getState());

                    if(CloudPayAccountDepositOrderEnum.State.Finish.index().equals(order.getState())) {
                        if (CloudPayAccountService.self().recharge(order)) {
                            JdbcSession.commit();
                            log.info("{{0}}账号充值成功，充值金额：{{1}}", order.getAccountId(), order.getPayMoney());
                        }
                    }else{
                        JdbcSession.commit();
                    }
                }else{
                    log.error("修改终端订单失败，订单信息：{{0:json}}",order);
                }
                //只要返回结果则同步成功
                result = true;
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        } finally {
            JdbcSession.end();
        }
        return result;
    }

    public boolean refund(CloudPayAccountDepositOrder order) throws LogicException {
        //TODO 需要判断支付宝退款
        CloudPayAccount cloudPayAccount = CloudPayAccountService.self().getById(order.getAccountId());
        if(cloudPayAccount.getWxpayAppId() == null){
            throw new LogicException("云支付账号未配置第三方支付");
        }
        WXPayConfig wxPayConfig = WXPayConfigService.self().getByAppId(cloudPayAccount.getWxpayAppId());
        if(wxPayConfig == null){
            throw new LogicException("未找到第三方支付(微信)");
        }
        DefaultWXPayConfig defaultWXPayConfig = ClassTools.copy(new DefaultWXPayConfig(),wxPayConfig);
        defaultWXPayConfig.setRefundNativeNotifyUrl(PayCallbackUtils.getRefundNativeNotifyUrl(wxPayConfig));

        try {
            WXPayNativeService wxpayNativeService = new WXPayNativeService(defaultWXPayConfig);

            WXPayDepositRefundOrder refundOrder = new WXPayDepositRefundOrder();
            refundOrder.setTradeNo(order.getTradeNo());
            refundOrder.setRefundMoney(order.getPayMoney());
            refundOrder.setNote("");

            WXPayNativeRefundResponse refundV3Response = wxpayNativeService.applyNativeRefund(order,refundOrder);
            if(refundV3Response != null && StringUtils.isNotBlank(refundV3Response.getStatus())){
                //TODO 退款处理
            }else{
                log.error("{{0}}账号充值创建微信Native支付返回失败，AppID = {{1}}，返回结果：{{2:json}}",cloudPayAccount.getId()
                        ,wxPayConfig.getAppId(),refundV3Response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public boolean waitToClose(String tradeNo){
        if(StringTools.isNotBlank(tradeNo)){
            Conditions conditions = new Conditions(CloudPayAccountDepositOrder.class);
            conditions.and().is("tradeNo",tradeNo);
            conditions.and().is("state",CloudPayAccountDepositOrderEnum.State.WaitPay.index());

            CloudPayAccountDepositOrder updateEntity = new CloudPayAccountDepositOrder();
            updateEntity.setState(CloudPayAccountDepositOrderEnum.State.Close.index());

            try {
                return dao.updateNotNull(updateEntity,conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean deleteByTradeNo(String tradeNo) throws LogicException{
        if(StringTools.isNotBlank(tradeNo)){
            CloudPayAccountDepositOrder order = getByTradeNo(tradeNo);
            if(order == null){
                throw new LogicException("充值订单不存在");
            }

            if(CloudPayAccountDepositOrderEnum.State.Finish.index().equals(order.getState())){
                throw new LogicException("订单已完成无法删除");
            }

            Conditions conditions = new Conditions(CloudPayAccountDepositOrder.class);
            conditions.and().is("tradeNo",tradeNo);
            conditions.and().is("state",order.getState());

            try {
                return dao.deleteByCondition(conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }
}
